﻿#include "Function.h"
#include "LockBitmap.h"

namespace ShadowMerger
{

    Bitmap *Function::combineIMG(const std::string &image, const std::string &shadow, std::vector<int> &imageOffsets, std::vector<int> &shadowOffsets, int dimension)
    {
        Bitmap *finalImage = new Bitmap(dimension, dimension);

        int center = finalImage->Width / 2;
//C# TO C++ CONVERTER NOTE: The following 'using' block is replaced by its C++ equivalent:
//ORIGINAL LINE: using (Graphics g = Graphics.FromImage(finalImage))
        {
            Graphics g = Graphics::FromImage(finalImage);
            //set background color
            g.Clear(Color::Black);

            Bitmap *shadowImage = new Bitmap(shadow);

            Rectangle tempVar(shadowOffsets[0] + center, shadowOffsets[1] + center, shadowImage->Width, shadowImage->Height);
            g.DrawImage(shadowImage, &tempVar);

//C# TO C++ CONVERTER TODO TASK: A 'delete shadowImage' statement was not added since shadowImage was passed to a method or constructor. Handle memory management manually.
        }

        finalImage = MirStyleTransparentBitLock(finalImage);
        finalImage = ChangeColorBitLock(finalImage);

//C# TO C++ CONVERTER NOTE: The following 'using' block is replaced by its C++ equivalent:
//ORIGINAL LINE: using (Graphics gr = Graphics.FromImage(finalImage))
        {
            Graphics gr = Graphics::FromImage(finalImage);
            Bitmap *mobImage = new Bitmap(image);
            mobImage->MakeTransparent(Color::Black);

            Rectangle tempVar2(imageOffsets[0] + center, imageOffsets[1] + center, mobImage->Width, mobImage->Height);
            gr.DrawImage(mobImage, &tempVar2);

//C# TO C++ CONVERTER TODO TASK: A 'delete mobImage' statement was not added since mobImage was passed to a method or constructor. Handle memory management manually.
        }

//C# TO C++ CONVERTER TODO TASK: A 'delete finalImage' statement was not added since finalImage was passed to a method or constructor. Handle memory management manually.
        return finalImage;
    }

    Bitmap *Function::Crop(Bitmap *bmp)
    {
        int w = bmp->Width, h = bmp->Height;

        std::function<bool(int)> allWhiteRow = [&] (int row)
        {
            for (int i = 0; i < w; ++i)
            {
                if (bmp->GetPixel(i, row).R != 0)
                {
                    return false;
                }
            }
            return true;
        };

        std::function<bool(int)> allWhiteColumn = [&] (int col)
        {
            for (int i = 0; i < h; ++i)
            {
                if (bmp->GetPixel(col, i).R != 0)
                {
                    return false;
                }
            }
            return true;
        };

        int topmost = 0;
        for (int row = 0; row < h; ++row)
        {
            if (allWhiteRow(row))
            {
                topmost = row;
            }
            else
            {
                break;
            }
        }

        int bottommost = 0;
        for (int row = h - 1; row >= 0; --row)
        {
            if (allWhiteRow(row))
            {
                bottommost = row;
            }
            else
            {
                break;
            }
        }

        int leftmost = 0, rightmost = 0;
        for (int col = 0; col < w; ++col)
        {
            if (allWhiteColumn(col))
            {
                leftmost = col;
            }
            else
            {
                break;
            }
        }

        for (int col = w - 1; col >= 0; --col)
        {
            if (allWhiteColumn(col))
            {
                rightmost = col;
            }
            else
            {
                break;
            }
        }

        int croppedWidth = rightmost - leftmost;
        int croppedHeight = bottommost - topmost;
        try
        {
            Bitmap *target = new Bitmap(croppedWidth, croppedHeight);
//C# TO C++ CONVERTER NOTE: The following 'using' block is replaced by its C++ equivalent:
//ORIGINAL LINE: using (Graphics g = Graphics.FromImage(target))
            {
                Graphics g = Graphics::FromImage(target);
                RectangleF tempVar(0, 0, croppedWidth, croppedHeight);
                RectangleF tempVar2(leftmost, topmost, croppedWidth, croppedHeight);
                g.DrawImage(bmp, &tempVar, &tempVar2, GraphicsUnit::Pixel);
            }

//C# TO C++ CONVERTER TODO TASK: A 'delete target' statement was not added since target was passed to a method or constructor. Handle memory management manually.
            return target;
        }
        catch (const std::runtime_error &ex)
        {
//C# TO C++ CONVERTER TODO TASK: This exception's constructor requires only one argument:
//ORIGINAL LINE: throw new Exception(string.Format("Values are topmost={0} btm={1} left={2} right={3}", topmost, bottommost, leftmost, rightmost), ex);
            throw std::runtime_error(std::string::Format("Values are topmost={0} btm={1} left={2} right={3}", topmost, bottommost, leftmost, rightmost));
        }
    }

    bool Function::IsOdd(int value)
    {
        return value % 2 != 0;
    }

    Bitmap *Function::ChangeColor(Bitmap *scrBitmap)
    {
        Color *newColor = Color::FromArgb(16, 8, 8);

        for (int i = 0; i < scrBitmap->Width; i++)
        {
            for (int j = 0; j < scrBitmap->Height; j++)
            {
                if (scrBitmap->GetPixel(i, j) != Color::FromArgb(0, 0, 0)) //8 12 8
                {
                    scrBitmap->SetPixel(i, j, newColor);
                }
            }
        }
        return scrBitmap;
    }

    Bitmap *Function::MirStyleTransparent(Bitmap *bmp)
    {
        Bitmap *myBitmap = new Bitmap(bmp);
        for (int i = 0; i < myBitmap->Width - 1; i++)
        {
            for (int j = 0; j < myBitmap->Height - 1; j++)
            {
                if (IsOdd(i) & IsOdd(j))
                {
                    myBitmap->SetPixel(i, j, Color::Black);
                }
                else if (!IsOdd(i) & !IsOdd(j))
                {
                    myBitmap->SetPixel(i, j, Color::Black);
                }
            }
        }

//C# TO C++ CONVERTER TODO TASK: A 'delete myBitmap' statement was not added since myBitmap was used in a 'return' or 'throw' statement.
        return myBitmap;
    }

    Bitmap *Function::ChangeColorBitLock(Bitmap *scrBitmap)
    {
        Color *newColor = Color::FromArgb(16, 8, 8);

        LockBitmap *lockBitmap = new LockBitmap(scrBitmap);
        lockBitmap->LockBits();

        for (int i = 0; i < lockBitmap->getWidth(); i++)
        {
            for (int j = 0; j < lockBitmap->getHeight(); j++)
            {
                if (lockBitmap->GetPixel(i, j) != Color::FromArgb(0, 0, 0)) //8 12 8
                {
                    lockBitmap->SetPixel(i, j, newColor);
                }
            }
        }
        lockBitmap->UnlockBits();

        delete lockBitmap;
        return scrBitmap;
    }

    Bitmap *Function::MirStyleTransparentBitLock(Bitmap *bmp)
    {
        LockBitmap *lockBitmap = new LockBitmap(bmp);
        lockBitmap->LockBits();

        for (int i = 0; i < lockBitmap->getWidth() - 1; i++)
        {
            for (int j = 0; j < lockBitmap->getHeight() - 1; j++)
            {
                if (IsOdd(i) & IsOdd(j))
                {
                    lockBitmap->SetPixel(i, j, Color::Black);
                }
                else if (!IsOdd(i) & !IsOdd(j))
                {
                    lockBitmap->SetPixel(i, j, Color::Black);
                }
            }
        }
        lockBitmap->UnlockBits();

        delete lockBitmap;
        return bmp;
    }

    Bitmap *Function::Mir3StyleShadow(Color *colour, Image *Path)
    {
        Bitmap *mi;
        mi = new Bitmap(Path);
        int tempWidth = mi->Width; //trueSize.Width
        int tempHeight = mi->Height; //trueSize.Height

        Bitmap *Temp = new Bitmap(tempWidth + tempHeight / 2, tempHeight);

        // Render Mir 3 Shadow / Far
        int DestY, DestX;
        for (int Y = 0; Y < tempHeight; Y++)
        {
            if (Y % 2 == 1)
            {
                continue;
            }
            DestY = Y / 2 + Temp->Height / 2 - 3;
            for (int X = 0; X < tempWidth; X++)
            {
                if (mi->GetPixel(X, Y)->Name == "0")
                {
                    continue;
                }
                DestX = X + (Temp->Height - Y) / 2;
                Temp->SetPixel(DestX, DestY, colour);
            }
        }

        // Cut out shadow behind mob
        for (int X = 0; X < mi->Width; X++)
        {
            for (int Y = 0; Y < mi->Height; Y++)
            {
                if (mi->GetPixel(X, Y)->Name != "0")
                {
                    Temp->SetPixel(X, Y, Color::Transparent);
                }
            }
        }

//C# TO C++ CONVERTER TODO TASK: A 'delete Temp' statement was not added since Temp was used in a 'return' or 'throw' statement.
        delete mi;
        return Temp;
    }

    Image *Function::SetImageOpacity(Image *image, float opacity)
    {
        try
        {
            //create a Bitmap the size of the image provided  
            Bitmap *bmp = new Bitmap(image->Width, image->Height);

            //create a graphics object from the image  
//C# TO C++ CONVERTER NOTE: The following 'using' block is replaced by its C++ equivalent:
//ORIGINAL LINE: using (Graphics gfx = Graphics.FromImage(bmp))
            {
                Graphics gfx = Graphics::FromImage(bmp);

                //create a color matrix object  
                ColorMatrix *matrix = new ColorMatrix();

                //set the opacity  
                matrix->Matrix33 = opacity;

                //create image attributes  
                ImageAttributes *attributes = new ImageAttributes();

                //set the color(opacity) of the image  
                attributes->SetColorMatrix(matrix, ColorMatrixFlag::Default, ColorAdjustType::Bitmap);

                //now draw the image  
                Rectangle tempVar(0, 0, bmp->Width, bmp->Height);
                gfx.DrawImage(image, &tempVar, 0, 0, image->Width, image->Height, GraphicsUnit::Pixel, attributes);

//C# TO C++ CONVERTER TODO TASK: A 'delete attributes' statement was not added since attributes was passed to a method or constructor. Handle memory management manually.
//C# TO C++ CONVERTER TODO TASK: A 'delete matrix' statement was not added since matrix was passed to a method or constructor. Handle memory management manually.
            }

//C# TO C++ CONVERTER TODO TASK: A 'delete bmp' statement was not added since bmp was passed to a method or constructor. Handle memory management manually.
            return bmp;
        }
        catch (const std::runtime_error &ex)
        {
            MessageBox::Show(ex.what());
            return nullptr;
        }
    }

DateTime Function::Benchmark::startDate = DateTime::MinValue;
DateTime Function::Benchmark::endDate = DateTime::MinValue;

    TimeSpan Function::Benchmark::getSpan()
    {
        return endDate.Subtract(startDate);
    }

    void Function::Benchmark::Start()
    {
        startDate = DateTime::Now;
    }

    void Function::Benchmark::End()
    {
        endDate = DateTime::Now;
    }

    double Function::Benchmark::GetSeconds()
    {
        if (endDate == DateTime::MinValue)
        {
            return 0.0;
        }
        else
        {
            return getSpan().TotalSeconds;
        }
    }
}
